package com.todo.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.Date;

/**
 * JWT（JSON Web Token）工具类
 * 提供JWT令牌的生成、验证、解析等功能
 * 用于用户身份认证和授权
 */
@SuppressWarnings("all")
@Component
public class JwtUtil {

    // 从配置文件读取JWT密钥
    @Value("${jwt.secret}")
    private String secret;

    // 从配置文件读取JWT过期时间（秒）
    @Value("${jwt.expiration}")
    private Long expiration;

    /**
     * 获取JWT签名密钥
     * 使用HMAC-SHA算法生成密钥
     * @return SecretKey 签名密钥
     */
    private SecretKey getSigningKey() {
        // 将密钥字符串转换为字节数组
        byte[] keyBytes = secret.getBytes(StandardCharsets.UTF_8);
        // 使用HMAC-SHA算法生成密钥
        return Keys.hmacShaKeyFor(keyBytes);
    }

    /**
     * 生成JWT令牌
     * @param userId 用户ID
     * @return String JWT令牌字符串
     */
    public String generateToken(Long userId) {
        // 获取当前时间
        Date now = new Date();
        // 计算过期时间（当前时间 + 配置的过期时间）
        Date expiryDate = new Date(now.getTime() + expiration * 1000);

        // 构建并生成JWT令牌
        return Jwts.builder()
                .setSubject(String.valueOf(userId))    // 设置主题（用户ID）
                .setIssuedAt(now)                      // 设置签发时间
                .setExpiration(expiryDate)             // 设置过期时间
                .signWith(getSigningKey(), SignatureAlgorithm.HS512)  // 使用HS512算法签名
                .compact();                            // 生成最终的JWT字符串
    }

    /**
     * 从JWT令牌中解析用户ID
     * @param token JWT令牌
     * @return Long 用户ID
     * @throws RuntimeException 当令牌无效或解析失败时抛出异常
     */
    public Long getUserIdFromToken(String token) {
        // 解析JWT令牌获取Claims
        Claims claims = Jwts.parserBuilder()
                .setSigningKey(getSigningKey())  // 设置签名密钥
                .build()
                .parseClaimsJws(token)           // 解析JWT
                .getBody();                      // 获取Claims主体
        
        // 从Claims中获取用户ID并转换为Long类型
        return Long.parseLong(claims.getSubject());
    }

    /**
     * 验证JWT令牌是否有效
     * @param token JWT令牌
     * @return boolean true-有效，false-无效
     */
    public boolean validateToken(String token) {
        try {
            // 尝试解析JWT令牌
            Jwts.parserBuilder()
                    .setSigningKey(getSigningKey())  // 设置签名密钥
                    .build()
                    .parseClaimsJws(token);          // 解析JWT
            return true;  // 解析成功，令牌有效
        } catch (Exception e) {
            // 解析失败，令牌无效（可能是签名错误、格式错误或已过期）
            return false;
        }
    }

    /**
     * 检查JWT令牌是否已过期
     * @param token JWT令牌
     * @return boolean true-已过期，false-未过期
     */
    public boolean isTokenExpired(String token) {
        try {
            // 解析JWT令牌获取Claims
            Claims claims = Jwts.parserBuilder()
                    .setSigningKey(getSigningKey())  // 设置签名密钥
                    .build()
                    .parseClaimsJws(token)           // 解析JWT
                    .getBody();                      // 获取Claims主体
            
            // 比较过期时间与当前时间
            return claims.getExpiration().before(new Date());
        } catch (Exception e) {
            // 解析失败，视为已过期
            return true;
        }
    }
} 